package com.steve.mac.tools.java8test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * designed by Steve Ke on 2017/12/10.
 *
 * @author Steve Ke
 *         e-mail  huangke7296@foxmail.com
 *         github  https://github.com/KoreHuang
 *         oschina https://git.oschina.net/steveKe
 * @version JDK 1.8.0_111
 * @since 2017/12/10
 */
public class StreamTest {
    /**
     * Stream Java8新特性,是对集合功能的增强。专注于对集合对象集合对象进行便利、高效的聚合操作或者大批量的数据处理操作
     * Stream 不会存储元素，元素存储在底层集合或者根据需要产生
     * Stream 操作符不改变源对象。级联调用产生一个持有结果的新 Stream
     * Stream 操作可能会延迟执行，意味着可能会等到需要结果的时候才执行
     * Stream 操作分为三部分：
     *      1.创建一个 Stream
     *      2.在一个或者多个操作中将指定的 Stream 转换为另外一个 Stream的中间操作
     *      3.通过终止方法产生计算结果，强制调用之前的延迟操作立即执行，之后 Stream 就不可以再次被使用
     *
     *          Intermediate 中间操作包括 filter()、distinct()、sorted()、map()、flatMap()等，一般都是对数据集合的分段整理（过滤、排序、抽取、匹配等）
     *
     *          Terminal 终止操作往往是完成对数据集中完整数据的处理，如：forEach()、allMatch()、findAny()、findFirst()，数值计算类方法
     *          sum()、max()、min()、avg()等等。终止方法也可以是对集合的处理，如 reduce()、collect()等。reduce()方法处理完毕
     *          每次产生新的结果集,collect()方法在元数据集的基础上进行更新，过程中不产生新数据集(此数据集非数据结构)
     */

    public static List<String> strDataSource=null;
    public static List<Integer> intDataSource=null;

    static {
        String[] intermediate=("map、 filter、 distinct、 sorted、 " +
                "peek、 limit、 skip、 parallel、 sequential、 " +
                "unordered").split("、 ");

        strDataSource= Arrays.asList(intermediate);
        intDataSource=Arrays.asList(1,2,3,4,5,6,7,8,9,0);
    }

    /**
     * Stream 的 map 操作按照 1:1 映射关系，对输入的每个元素按照传入的 lambda 规则转化为另一个元素按顺序置入新计算流
     */
    public void testMap(){
        /**
         * 代码段将集合中的所有字符串元素变为大写,原始集合不变
         */
        List outProd=strDataSource
                .parallelStream()
                .map(e->e.toUpperCase())
                .collect(ArrayList::new,List::add,List::addAll);

        outProd
                .parallelStream()
                .forEach(System.out::println);
        strDataSource
                .parallelStream()
                .forEach(System.out::println);
        /**
         * 代码段将集合中的元素转化为平方数，原始结合不变
         */

        outProd=intDataSource
                .parallelStream()
                .map(e->e*e)
                .collect(Collectors.toList());
        outProd
                .parallelStream()
                .forEach(System.out::println);
        strDataSource
                .parallelStream()
                .forEach(System.out::println);

    }

    /**
     * Stream 的 flatMap 操作把 input Stream 中的层级结构扁平化，就是将最底层元素抽出来放到一起，最终 output 的
     * 新 Stream 里面已经没有 List 了，都是直接的数字
     */
    public void testFlatMap(){
        Stream<List<Integer>> inputStream=Stream
                .of(
                        Arrays.asList(1,2,3),
                        Arrays.asList(4,5,6),
                        Arrays.asList(7,8,9)
                );
        List prod=inputStream
                .parallel()
                .flatMap(childList->childList.stream())
                .map(e->e*e)
                .collect(Collectors.toList());
        prod.forEach(System.out::println);
    }

    /**
     *  Stream 的 filter 操作对原始 Stream 进行某项测试，通过测试的元素被留下来生成一个新 Stream。
     */
    public void testFilter(){
        Integer []numbers={1,2,3,4,5,6};
        Stream
                .of(numbers)
                .filter(e -> e%2 ==0)
                .forEach(System.out::println);
    }

    /**
     *  Stream 的 reduce 操作把 Stream 元素组合起来
     */
    public void testReduce(){
        // 字符串连接，concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        // 求最小值，minValue = -3.0
        double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        // 求和，sumValue = 10, 有起始值
        int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
        // 求和，sumValue = 10, 无起始值
        sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        // 过滤，字符串连接，concat = "ace"
        concat = Stream.of("a", "B", "c", "D", "e", "F").
                filter(x -> x.compareTo("Z") > 0).
                reduce("", String::concat);
    }

    public static void main(String []args){
        StreamTest testEntity=StreamTest.getNewInstance(StreamTest::new);
        testEntity.testMap();
        testEntity.testFlatMap();
    }

    /**
     * 静态方法创建对象
     * @param supplier
     * @return
     */
    public static StreamTest getNewInstance(Supplier<StreamTest> supplier){
        return supplier.get();
    }

}
